package net.quanter.shield.common.dto.result.wapper;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.ToString;
import net.quanter.shield.common.dto.result.ResultDTO;
import org.jetbrains.annotations.NotNull;

/**
 * Map类型通用返回DTO
 *
 * @author 王老实
 * @since 1.3.12.RELEASE
 */
@Schema(description = "Map类型通用返回DTO")
@ToString
public class ResultDTOMapWrapper<K extends Serializable, V extends Serializable> implements Map<K, V> {
    @Getter
    private final ResultDTO<Map<K, V>> resultDTO;

    public ResultDTOMapWrapper(ResultDTO<Map<K, V>> resultDTO) {
        this.resultDTO = resultDTO == null ? emptyMap() : resultDTO;
    }

    public static <K extends Serializable, V extends Serializable> ResultDTO<Map<K, V>> emptyMap() {
        return new ResultDTO<>(new ConcurrentHashMap<>());
    }

    public static <K extends Serializable, V extends Serializable> ResultDTOMapWrapper<K, V> emptyMapWapper() {
        return new ResultDTOMapWrapper(emptyMap());
    }

    public Map<K,V> getData() {
        return resultDTO.getData();
    }

    @Override
    public V put(K k, V v) {
        return resultDTO.get().map(x -> x.put(k, v)).orElse(null);
    }

    public ResultDTOMapWrapper<K, V> putValue(K k, V v) {
        put(k, v);
        return this;
    }

    @Override
    public V remove(Object key) {
        return resultDTO.get().map(x -> x.remove(key)).orElse(null);
    }

    @Override
    public void putAll(@NotNull Map<? extends K, ? extends V> m) {
        resultDTO.get().ifPresent(x -> x.putAll(m));
    }

    @Override
    public V get(Object k) {
        return resultDTO.get().map(x -> x.get(k)).orElse(null);
    }

    @Override
    public boolean isEmpty() {
        return resultDTO.get().map(Map::isEmpty).orElse(false);
    }

    @Override
    public boolean containsKey(Object key) {
        return resultDTO.get().map(x -> x.containsKey(key)).orElse(false);
    }

    @Override
    public boolean containsValue(Object value) {
        return resultDTO.get().map(x -> x.containsValue(value)).orElse(false);
    }

    @Override
    public int size() {
        return resultDTO.get().map(Map::size).orElse(0);
    }

    @Override
    public void clear() {
        resultDTO.get().ifPresent(Map::clear);
    }

    @Override
    public void forEach(BiConsumer<? super K, ? super V> action) {
        resultDTO.get().ifPresent(x -> x.forEach(action));
    }

    @Override
    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        resultDTO.get().ifPresent(x -> x.replaceAll(function));
    }

    @Override
    public V putIfAbsent(K key, V value) {
        return resultDTO.get().map(x -> x.putIfAbsent(key, value)).orElse(null);
    }

    @Override
    public boolean remove(Object key, Object value) {
        return resultDTO.get().map(x -> x.remove(key, value)).orElse(false);
    }

    @Override
    public boolean replace(K key, V oldValue, V newValue) {
        return resultDTO.get().map(x -> x.replace(key, oldValue, newValue)).orElse(false);
    }

    @Override
    public V replace(K key, V value) {
        return resultDTO.get().map(x -> x.replace(key, value)).orElse(null);
    }

    @Override
    public V computeIfAbsent(K key, @NotNull Function<? super K, ? extends V> mappingFunction) {
        return resultDTO.get().map(x -> x.computeIfAbsent(key, mappingFunction)).orElse(null);
    }

    @Override
    public V computeIfPresent(K key, @NotNull BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        return resultDTO.get().map(x -> x.computeIfPresent(key, remappingFunction)).orElse(null);
    }

    @Override
    public V compute(K key, @NotNull BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        return resultDTO.get().map(x -> x.compute(key, remappingFunction)).orElse(null);
    }

    @Override
    public V merge(K key, @NotNull V value, @NotNull BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        return resultDTO.get().map(x -> x.merge(key, value, remappingFunction)).orElse(null);
    }

    @Override
    public @NotNull Set<Map.Entry<K, V>> entrySet() {
        return resultDTO.get().map(Map::entrySet).orElse(new ConcurrentHashMap<K, V>().entrySet());
    }

    @Override
    public @NotNull Set<K> keySet() {
        return resultDTO.get().map(Map::keySet).orElse(new ConcurrentHashMap<K, V>().keySet());
    }

    @Override
    public @NotNull Collection<V> values() {
        return resultDTO.get().map(Map::values).orElse(new ConcurrentHashMap<K, V>().values());
    }

    @Override
    public V getOrDefault(Object key, V defaultValue) {
        return resultDTO.get().map(x -> x.getOrDefault(key, defaultValue)).orElse(defaultValue);
    }

}
